Skip to content

Vue Router 与前端路由

作者:青见春山
发表于:2026-07-29
字数统计:8500 字
预计阅读29分钟

涵盖 Vue Router 两种模式、核心 API、路由守卫、懒加载、动态路由;以及前端路由底层原理、手写简易路由。原文件"vue-router"和"前端路由"两节合并到本文。


第一部分:前端路由基础

标准面试回答(1 分钟)

前端路由是指在前端维护 URL 和视图的映射关系,在不刷新页面的情况下,根据 URL 变化动态渲染对应组件的机制,核心是实现 SPA 的页面切换体验

前端路由的底层原理基于两种实现方式:

第一种,Hash 模式:利用 URL 中 # 后面的部分(hash)不会触发页面刷新的特性,通过监听 hashchange 事件来感知 hash 变化,然后根据当前 hash 渲染对应组件。hash 值的变化不会发送到服务端,因此兼容性好,不需要服务端额外配置,但 URL 看起来不够美观。

第二种,History 模式:基于 HTML5 的 History API,核心是 pushStatereplaceState 方法,可以改变浏览器的 URL 而不刷新页面,同时通过监听 popstate 事件来响应用户的前进后退操作。这种方式 URL 更干净,但需要服务端配合做兜底配置(将所有路由指向 index.html),否则刷新页面会 404。

核心实现要素

  • 路由映射表:存储路径和组件的对应关系
  • 路由监听:hash 变化或 popstate 事件触发路由更新
  • 路由匹配:根据当前 URL 找到对应的组件
  • 视图渲染:将匹配到的组件渲染到指定容器中

前端路由的价值:实现页面切换无刷新,提升用户体验;可以维护浏览历史记录,支持前进后退;支持嵌套路由、路由参数、权限控制等复杂场景。

Vue Router、React Router 等框架路由库都是在这个原理基础上封装了更丰富的 API 和功能。

20 秒极简版

前端路由是 SPA 的核心机制,通过监听 URL 变化渲染对应组件,无需刷新页面。两种实现方式:Hash 模式靠 #hashchange,兼容性好;History 模式靠 pushStatepopstate,URL 更干净但需服务端配合。

追问 1:pushState、replaceState 与 popstate

pushState 和 replaceState 的区别

  • pushState:在历史记录栈中添加一条新记录,浏览器的"后退"按钮可以回到上一个状态
  • replaceState替换当前历史记录,不会增加记录条数,替换后无法通过"后退"回到被替换前的状态

两者的共同点是都不会触发页面刷新,都只改变 URL。

popstate 触发时机

  • 用户点击浏览器的"前进""后退"按钮时触发
  • 在 JS 中调用 history.back()history.forward()history.go() 时触发
  • 注意:直接调用 pushStatereplaceState 不会触发 popstate 事件

所以在前端路由的实现中,调用 pushState 改变 URL 后,需要手动执行路由匹配和视图更新;而 popstate 事件监听用于处理用户的前进后退操作。

追问 2:Hash 模式和 History 模式在 SEO 上的差异

Hash 模式对 SEO 不友好:搜索引擎爬虫在抓取页面时,# 后面的内容通常不会被发送到服务端,也不会被索引。对于需要 SEO 的网站(如内容展示类、官网),Hash 模式会导致页面无法被搜索引擎收录。

History 模式对 SEO 相对友好:URL 是真实路径,搜索引擎会将其视为独立的页面资源进行抓取。但需要服务端做 SSR(服务端渲染)或预渲染才能真正对 SEO 生效——如果只是前端 SPA + History 模式,页面内容仍然是 JS 动态渲染的,爬虫可能执行不了 JS,所以 SEO 效果有限。

结论

  • 对内后台管理系统、不需要 SEO 的页面 → Hash 模式足够,配置简单
  • 对外官网、营销页、需要 SEO 的 SPA → 用 History 模式 + SSR(如 Nuxt.js)或预渲染方案
  • 单纯 History 模式不做 SSR,SEO 提升有限

追问 3:手写简易前端路由

JavaScript
class SimpleRouter {
  constructor(routes) {
    this.routes = routes
    this.currentPath = ''

    // 监听 hash 变化
    window.addEventListener('hashchange', this.onHashChange.bind(this))

    // 初始化
    this.onHashChange()
  }

  onHashChange() {
    // 获取 hash,去掉开头的 #
    let hash = window.location.hash.slice(1)
    if (!hash) hash = '/'      // 默认首页
    this.currentPath = hash

    // 匹配路由,找不到就 404
    const route = this.routes[hash]
    if (route) {
      this.render(route.component)
    } else {
      this.render(this.routes['404']?.component || '<div>404</div>')
    }
  }

  render(component) {
    const app = document.getElementById('app')
    if (typeof component === 'string') {
      app.innerHTML = component
    } else if (component.render) {
      // 假设组件有 render 方法
      app.innerHTML = component.render()
    }
  }

  push(path) {
    window.location.hash = path
  }
}

// 使用
const router = new SimpleRouter({
  '/': { component: '<div>首页</div>' },
  '/about': { component: '<div>关于</div>' }
})

History 模式版本需要监听 popstate,用 pushState 改 URL,并处理服务端 404 问题。

易错点

  • 混淆"前端路由"和"后端路由":前端路由是客户端维护 URL 和视图映射,后端路由是服务端根据路径返回资源
  • 只讲用法不讲原理:说不清 hashchangepushState 的区别
  • History 模式刷新 404 的原因说不清
  • popstate 触发时机答错:常见错误是"pushState 也会触发 popstate"
  • 忽略 SEO 与 SSR 的关系:只说"History 模式对 SEO 友好",不提"需要 SSR"
  • 手写路由时遗漏默认路由和 404
  • 混淆 window.location 的属性和方法

第二部分:Vue Router

标准面试回答(1 分钟)

Vue Router 是 Vue.js 官方的路由管理器,用于构建单页面应用(SPA),核心能力是在不刷新页面的情况下,根据 URL 的变化渲染对应的组件,同时提供路由守卫、导航控制、路由懒加载等高级功能

把 Vue Router 的核心知识分成三个维度:

两种模式

  • Hash 模式:默认模式,URL 中带 #,通过监听 hashchange 事件实现路由切换。兼容性好,但看起来不够美观,# 后面的内容不会发送到服务端。
  • History 模式:基于 HTML5 History API,使用 pushStatereplaceState,URL 更干净。但需要服务端配合做兜底配置(比如 nginx 配置 try_files),否则刷新会 404。

核心组成

  • 路由配置routes 数组,定义路径和组件的映射关系
  • 路由视图<router-view> 作为组件渲染的出口
  • 路由链接<router-link> 替代 <a> 标签,支持导航高亮
  • 路由对象$route(当前路由信息)和 $router(路由实例,用于编程式导航)

高级特性

  • 路由守卫:全局守卫(beforeEachafterEach)、路由独享守卫、组件内守卫(beforeRouteEnter 等),用于权限控制、登录拦截
  • 路由懒加载:结合动态 import,实现按需加载,优化首屏性能
  • 动态路由/user/:id 这种参数化路径
  • 嵌套路由:在组件内部嵌套 <router-view>,实现二级菜单等布局
  • 命名视图:一个页面多个 <router-view> 按 name 分别渲染

Vue Router 3.x 对应 Vue 2,Vue Router 4.x 对应 Vue 3。Vue Router 4 中 API 有变化,比如 new Router 改为 createRoutermode 改为 history 配置,路由守卫的写法也略有调整。

20 秒极简版

Vue Router 是 Vue 的官方路由库,核心是监听 URL 变化渲染对应组件,实现 SPA。两种模式:Hash(带 #,兼容性好)和 History(需服务端配置)。关键概念:路由配置、<router-view><router-link>、编程式导航、路由守卫、懒加载。

追问 1:History 模式刷新为什么会 404?

原因:Hash 模式下,# 后面的内容不会发送到服务端,所有路由请求其实都是请求 index.html,由前端路由接管。而 History 模式下,URL 是真实的路径,比如 /user/123。刷新页面时,浏览器会向服务端请求这个路径,如果服务端没有对应的资源,就会返回 404。

解决方案:需要在服务端配置"所有路由都返回 index.html",让前端路由自己处理。

常见的配置:

Nginx

Plain
location / {
  try_files $uri $uri/ /index.html;
}

Node.js (Express)

JavaScript
app.use(express.static('dist'))
app.get('*', (req, res) => {
  res.sendFile(path.resolve(__dirname, 'dist', 'index.html'))
})

另外要注意:History 模式下,静态资源(JS、CSS)的路径需要使用绝对路径或正确配置 publicPath,否则刷新后资源也会 404。

追问 2:路由守卫怎么实现登录拦截?

全局前置守卫 beforeEach 实现登录拦截。完整流程:

JavaScript
router.beforeEach((to, from, next) => {
  // 1. 判断是否需要登录
  const requiresAuth = to.meta.requiresAuth

  // 2. 获取登录状态(通常从 store 或 localStorage 取 token)
  const isLoggedIn = store.state.user.isLoggedIn

  // 3. 路由拦截逻辑
  if (requiresAuth && !isLoggedIn) {
    // 未登录,跳转到登录页,并携带目标路由以便登录后跳回
    next({
      path: '/login',
      query: { redirect: to.fullPath }
    })
  } else if (to.path === '/login' && isLoggedIn) {
    // 已登录访问登录页,重定向到首页
    next('/')
  } else {
    // 正常放行
    next()
  }
})

关键细节

  • 必须调用 next()next(path),否则路由会卡住
  • 路由元信息 meta 用于标记哪些路由需要登录
  • 登录成功后,用 router.push(redirect) 跳回目标页面
  • 权限更复杂的场景,还可以在守卫中动态添加路由(router.addRoute

追问 3:动态路由怎么添加?路由懒加载怎么实现?

动态路由添加:常用于权限控制,根据用户角色动态生成路由。

Vue Router 3 中用 router.addRoutes,Vue Router 4 中用 router.addRoute

JavaScript
// 根据权限动态添加
const adminRoutes = [
  { path: '/admin', component: () => import('@/views/Admin.vue') }
]
adminRoutes.forEach(route => router.addRoute(route))

注意:动态添加的路由需要配合 router.push 或重新触发导航才能生效。一般会在登录后获取权限列表,动态添加路由后再跳转。

路由懒加载:使用动态 import,让路由组件在访问时才加载,而不是打包到主 bundle 里。

JavaScript
const routes = [
  {
    path: '/user',
    component: () => import('@/views/User.vue')
  }
]

结合 webpack 的魔法注释可以自定义 chunk 名:

JavaScript
component: () => import(/* webpackChunkName: "user" */ '@/views/User.vue')

在 Vue Router 4 中,还可以配合 Vue 3 的异步组件 defineAsyncComponent,但直接 () => import() 更简洁。

懒加载的优点是按需加载,减小首屏体积,缺点是切换时可能有加载延迟,通常配合骨架屏或 loading 优化体验。

易错点

  • 模式原理讲不清楚:只说"Hash 模式带 #,History 不带",说不清底层依赖(hashchange vs pushState)和刷新 404 的原因
  • History 模式服务端配置答不上来
  • 路由守卫忘记 next:写守卫时忘记调用 next 或者逻辑分支漏掉 next
  • 混淆 $route$router$route 是路由信息对象,$router 是路由实例
  • 动态路由 API 版本混淆:Vue Router 3 的 addRoutes 和 Vue Router 4 的 addRoute 用法不同
  • 路由守卫中直接操作 location.href:会触发页面刷新,失去 SPA 意义
  • 懒加载的 chunk 命名说不清楚
  • 嵌套路由和命名视图混淆:嵌套路由是路由层级嵌套,命名视图是同一级渲染多个视图

Vue 3 中 keep-alive 与 Router 的结合

详见 06-Vue scoped、keep-alive、插槽、过滤器 的"keep-alive 与 Router"部分。


关联文档